package com.collabscm.pf.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.springframework.util.Assert;

import com.collabscm.pf.exception.BaseRuntimeException;
import com.collabscm.pf.exception.PlatformExceptionConstants;

/**
 * 反射工具类，提供各类反射相关的方法
 * @author Zeng Raoxing
 */
public class ReflectionUtils {
	private final static ClassLoader CLASS_LOADER = ReflectionUtils.class.getClassLoader();

	/**
	 * 根据类名进行实例化
	 * @param className 待实例化的类
	 * @return 返回实例化的对象
	 */
	public static Object instanceFromClassName(String className) {
		Class<?> clazz = getClass(className);
		return instance(clazz);
	}
	
	/**
	 * 根据类名进行实例化，并且验证待实例化的类是parentClass的子类
	 * @param className   待实例化的类
	 * @param parentClass 目标类型
	 * @return 返回实例化的对象，
	 */
	public static Object instanceFromClassName(String className, Class<?> parentClass) {
		Class<?> clazz = getClass(className);
		if(clazz.isAssignableFrom(parentClass)) {
			throw new ReflectException(clazz + "不是" + parentClass + "的子类。");
		}
		return instance(clazz);
	}
	
	/**
	 * 根据类的全路径名获得Class对象
	 * @param className 类的全路径名，例如：com.leepweb.Test
	 */
	public static Class<?> getClass(String className) {
		try {
			return CLASS_LOADER.loadClass(className);
		} catch (ClassNotFoundException e) {
			throw new ReflectException("无法得到加载" + className, e);
		}
	}
	
	/**
	 * 实例化Class对象
	 * @param clazz Class对象
	 */
	public static Object instance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new ReflectException("实例化" + clazz + "时发生异常", e);
		} catch (IllegalAccessException e) {
			throw new ReflectException("实例化" + clazz + "时发生异常", e);
		}
	}
	
	/**
	 * 实例化Class对象
	 * @param clazz
	 * @param parameterTypes
	 * @param initargs
	 * @return
	 */
	public static Object instance(Class<?> clazz, Class<?>[] parameterTypes, Object[] initargs) {
		if(parameterTypes.length != initargs.length) {
			throw new ReflectException("实例化" + clazz + "所传递的参数与初始参数不一致，其中：parameterTypes的长度为" + parameterTypes.length + ", initargs的长度为" + initargs.length);
		}
		Constructor<?> c = getDeclaredConstructor(clazz, parameterTypes);
		try {
			return c.newInstance(initargs);
		} catch (IllegalArgumentException e) {
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + ObjectUtils.arrayToString(initargs), e);
		} catch (InstantiationException e) {
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + ObjectUtils.arrayToString(initargs), e);
		} catch (IllegalAccessException e) {
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + ObjectUtils.arrayToString(initargs), e);
		} catch (InvocationTargetException e) {
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + ObjectUtils.arrayToString(initargs), e);
		}
	}
	
	/**
	 * 得到类的指定构造函数
	 * @param clazz
	 * @param parameterTypes
	 * @return
	 */
	public static Constructor<?> getDeclaredConstructor(Class<?> clazz, Class<?>... parameterTypes) {
		try {
			return clazz.getDeclaredConstructor(parameterTypes);
		} catch (SecurityException e) {
			throw new ReflectException("试图得到" + clazz + "的" + ObjectUtils.arrayToString(parameterTypes) + "构造函数是报错。", e);
		} catch (NoSuchMethodException e) {
			throw new ReflectException("试图得到" + clazz + "的" + ObjectUtils.arrayToString(parameterTypes) + "构造函数是报错。", e);
		}
	}
	
	/**
	 * 得到指定类中的方法，如果没有此方法，那么返回null，否则将返回正确Method对象
	 * @param clazz          类
	 * @param name           方法名
	 * @param parameterTypes 参数列表
	 * @return
	 */
	public static Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
		try {
			return clazz.getMethod(name, parameterTypes);
		} catch (SecurityException e) {
			throw new ReflectException("试图从" + clazz + "中得到" + name + "(" + ObjectUtils.arrayToString(parameterTypes) + ")方法发生异常。", e);
		} catch (NoSuchMethodException e) {
			throw new ReflectException("试图从" + clazz + "中得到" + name + "(" + ObjectUtils.arrayToString(parameterTypes) + ")方法发生异常。", e);
		}
	}
	
	/**
	 * 调用方法
	 * @param method
	 * @param obj
	 * @param args
	 * @return
	 */
	public static Object invokeMethod(Method method, Object obj, Object... args) {
		Assert.notNull(method, "调用的方法对象不能为null");
		try {
			return method.invoke(obj, args);
		} catch (IllegalArgumentException e) {
			throw new ReflectException("调用" + ObjectUtils.toString(obj) + "的" + method + "，参数为：" + ObjectUtils.arrayToString(args), e);
		} catch (IllegalAccessException e) {
			throw new ReflectException("调用" + ObjectUtils.toString(obj) + "的" + method + "，参数为：" + ObjectUtils.arrayToString(args), e);
		} catch (InvocationTargetException e) {
			throw new ReflectException("调用" + ObjectUtils.toString(obj) + "的" + method + "，参数为：" + ObjectUtils.arrayToString(args), e);
		}
	}
	
	/**
	 * 根据属性名得到对应的Getter方法的名字
	 * @param propertyName
	 * @return
	 */
	public static String buildGetterMethodName(String propertyName) {
		return "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
	}
	
	/**
	 * 得到属性所对应的get方法
	 * 
	 * @param propertyName 属性名
	 * @param clazz        对应的Class类
	 * @return
	 */
	public static Method getGetterMethod(Class<?> clazz, String propertyName) {
		return getMethod(clazz, buildGetterMethodName(propertyName));
	}
	
}

/**
 * 反射调用异常，此异常类仅在ReflectUtils类中使用。
 * @author Zeng Raoxing
 */
class ReflectException extends BaseRuntimeException {
	private static final long serialVersionUID = 1L;
	public ReflectException(String logMessage) {
		super(logMessage, PlatformExceptionConstants.ReflectExceptionCode);
	}
	
	public ReflectException(String logMessage, Throwable cause) {
		super(logMessage, PlatformExceptionConstants.ReflectExceptionCode, cause);
	}
	
}
